/** <!--------------------------------------------------------------------------------------------->
 * @file SvnConnection.h
 *
 * GSvn - A Graphical Client for SVN
 * Copyright (C) 2012  Karl Krach, gsvn@bluespirit.la
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 <!---------------------------------------------------------------------------------------------> */

#ifndef SVN_CONNECTION_H
#define SVN_CONNECTION_H


// -- includes --
#include <QObject>
#include <QTime>
#include "SvnRevisionIdentifier.h"

// --- forward declarations ---
struct apr_pool_t;					// from apr-1.0/apr_pools.h : 60
typedef  off_t apr_off_t;			// from apr-1.0/apr.h : 362
struct svn_client_ctx_t;			// from subversion-1/svn_client.h : 816
struct svn_error_t;					// from subversion-1/svn_types.h : 67
typedef int svn_boolean_t;			// from subversion-1/svn_types.h : 245
struct svn_log_entry_t;				// from subversion-1/svn_types.h : 670
struct svn_auth_cred_simple_t;		// from subversion-1/svn_auth.h : 185
struct svn_auth_cred_username_t;	// from subversion-1/svn_auth.h : 209
class QUrl;
struct SvnHistoryListener;

// --- namespaces ---
// --- defines ---


/** <!--------------------------------------------------------------------------------------------->
 * The SvnConnection object is used to create a connection to the svn repository. Further more it
 * provides methods to access this repository, when once connected.
 *
 * @author	Karl Krach, <gsvn@bluespirit.la>
 * @since	2012-01-08
 <!---------------------------------------------------------------------------------------------> */
class SvnConnection : public QObject
{
	Q_OBJECT

	/* Inner Classes */
private:

	/** <!----------------------------------------------------------------------------------------->
	 * Container object to transfer the progress listener and to store the transfered bytes
	 <!-----------------------------------------------------------------------------------------> */
	struct SvnProgressContainer
	{
		/** <!------------------------------------------------------------------------------------->
		 * QTime object as a stopwatch, started when starting the svn..list command
		 <!-------------------------------------------------------------------------------------> */
		QTime m_oTime;

		/** <!------------------------------------------------------------------------------------->
		 * Number of bytes transfered
		 <!-------------------------------------------------------------------------------------> */
		int m_iTransfered;

		/** <!------------------------------------------------------------------------------------->
		 * Pointer to listener class (used for callback methods)
		 <!-------------------------------------------------------------------------------------> */
		SvnHistoryListener* m_pListener;

	};	// END struct SvnProgressContainer


	/* Con/-Destructors */
public:

	/** <!----------------------------------------------------------------------------------------->
	 * Creates the SvnConnection object
	 *
	 * @param pParent pointer to parent object
	 <!-----------------------------------------------------------------------------------------> */
	explicit SvnConnection(QObject *parent = 0);

	/** <!----------------------------------------------------------------------------------------->
	 * Deletes the SvnConnection object
	 <!-----------------------------------------------------------------------------------------> */
	~SvnConnection();


	/* Methods */
public:

	/** <!----------------------------------------------------------------------------------------->
	 * Initializes the SVN library, setups the client context and does the authentication.
	 <!-----------------------------------------------------------------------------------------> */
	bool Initialize() { return InitializeSvnLibrary() && SetupClientContext() && Authenticate(); }

	/** <!----------------------------------------------------------------------------------------->
	 * Requests the history data from the SVN server and returns it to the listner object.
	 *
	 * @param rNodeIdentifier (in) node, of which the history should be received
	 * @param pListener       (in) pointer to object, which receives the history data
	 * @returns false on error
	 <!-----------------------------------------------------------------------------------------> */
	bool GetCompleteHistory( const SvnRevisionIdentifier& rNodeIdentifier,
	                         SvnHistoryListener* pListener );

	/** <!----------------------------------------------------------------------------------------->
	 * Returns a URL from the given path. (The URL can also be invalid!)
	 *
	 * @param rPath (in) Path to convert to URL
	 * @returns a URL from the given path
	 <!-----------------------------------------------------------------------------------------> */
	QUrl CreateUrl( const QString& rPath );

	/** <!----------------------------------------------------------------------------------------->
	 * Returns a root URL from the given path. (The URL can also be invalid!)
	 *
	 * @param rPath (in) Path to get root-url for
	 * @returns the root-URL of the given path
	 <!-----------------------------------------------------------------------------------------> */
	QUrl CreateRootUrl( const QString& rPath );

	/** <!----------------------------------------------------------------------------------------->
	 * Returns true, if the linked library (lib_xxx.so) is compatible to the compiled library (lib_xx.a)
	 *
	 * @returns true, if the linked library is compatible to the compiled library
	 <!-----------------------------------------------------------------------------------------> */
	bool IsLibraryCompatible();

	/** <!----------------------------------------------------------------------------------------->
	 * Returns the version of the SVN library, which was linked to the application
	 *
	 * @returns the version of the SVN library, which was linked to the application
	 <!-----------------------------------------------------------------------------------------> */
	QString GetLinkedLibVersion();

	/** <!----------------------------------------------------------------------------------------->
	 * Returns the version of the SVN library, which is loaded to the application at runtime
	 *
	 * @returns the version of the SVN library, which is loaded to the application at runtime
	 <!-----------------------------------------------------------------------------------------> */
	QString GetLoadedLibVersion();


	/* Private Methods */
private:

	/** <!----------------------------------------------------------------------------------------->
	 * Initializes the SVN library
	 *
	 * @returns false, if the initilization failed
	 <!-----------------------------------------------------------------------------------------> */
	bool InitializeSvnLibrary();

	/** <!----------------------------------------------------------------------------------------->
	 * Setups the client context
	 *
	 * @returns false, if the setup failed
	 <!-----------------------------------------------------------------------------------------> */
	bool SetupClientContext();

	/** <!----------------------------------------------------------------------------------------->
	 * Make the client_ctx capable of authentication users
	 *
	 * @returns false, if the authentication failed
	 <!-----------------------------------------------------------------------------------------> */
	bool Authenticate();


	/* Private Static Methods */
private:

	/** <!----------------------------------------------------------------------------------------->
	 * Call back method to ask the user for login data
	 *
	 * @param pCredentials (out) Credentials to be written
	 * @param pBaton       (in)  Baton (in this case a pointer to SvnConnection object)
	 * @param strRealm     (in)  If realm is non-NULL, maybe use it in the prompt string.
	 * @param strUsername  (in)  Predefined username (if non-null, promt only for password)
	 * @param bMaySave     (in)  System daos not allow to save the credentials to disk
	 * @param pPool        (in)  Pool for memory management
	 <!-----------------------------------------------------------------------------------------> */
	static svn_error_t* PromtUserForLoginData( svn_auth_cred_simple_t** pCredentials, void* pBaton,
	                                           const char* strRealm, const char* strUsername,
	                                           svn_boolean_t bMaySave, apr_pool_t* pPool );

	/** <!----------------------------------------------------------------------------------------->
	 * Call back method to ask the user for username
	 *
	 * @param pCredentials (out) Credentials to be written
	 * @param pBaton       (in)  Baton (in this case a pointer to SvnConnection object)
	 * @param strRealm     (in)  If realm is non-NULL, maybe use it in the prompt string.
	 * @param bMaySave     (in)  System daos not allow to save the credentials to disk
	 * @param pPool        (in)  Pool for memory management
	 <!-----------------------------------------------------------------------------------------> */
	static svn_error_t* PromtUserForUsername( svn_auth_cred_username_t** pCredentials, void* pBaton,
	                                          const char* strRealm, svn_boolean_t bMaySave,
	                                          apr_pool_t* pPool );

	/** <!----------------------------------------------------------------------------------------->
	 * A user defined callback that subversion will call with a user defined baton to see if the
	 * current operation should be continued.
	 *
	 * @param pCancelBaton (in)  Baton (in this case a pointer to SvnConnection object)
	 <!-----------------------------------------------------------------------------------------> */
	static svn_error_t* CheckForCancelCallback( void* pCancelBaton );

	/** <!----------------------------------------------------------------------------------------->
	 * Call back method to transfer a history entry
	 *
	 * @param iProgress (in) Bytes which where transfered of this chunk
	 * @param iTotal    (in) Total bytes of this chunk
	 * @param pBaton    (in) Baton (in this case a pointer to SvnProgressContainer object)
	 * @param pPool     (in) Pool for memory management
	 <!-----------------------------------------------------------------------------------------> */
	static void TransferProgressInfo( apr_off_t iProgress, apr_off_t iTotal, void* pBaton,
	                                  apr_pool_t* pPool );

	/** <!----------------------------------------------------------------------------------------->
	 * Call back method to transfer a history entry
	 *
	 * @param pBaton       (in) Baton (in this case a pointer to SvnHistoryListener object)
	 * @param pLogEntry    (in) The log entry object to get the data from
	 * @param pPool        (in) Pool for memory management
	 <!-----------------------------------------------------------------------------------------> */
	static svn_error_t* TransferHistoryEntry( void* pBaton, svn_log_entry_t* pLogEntry,
	                                          apr_pool_t* pPool );


	/* Members */
private:

	/** <!----------------------------------------------------------------------------------------->
	 * Pool for APR's memory management
	 <!-----------------------------------------------------------------------------------------> */
	apr_pool_t* m_pPool;

	/** <!----------------------------------------------------------------------------------------->
	 * Client context object that represents a particular instance of an svn client. It is created
	 * from the m_pPool, and thus is deleted when the pool is destroyed.
	 <!-----------------------------------------------------------------------------------------> */
	svn_client_ctx_t* m_pContext;

	/** <!----------------------------------------------------------------------------------------->
	 * True, if this object was initialized (especially the SVN library)
	 <!-----------------------------------------------------------------------------------------> */
	bool m_bInitialized;

	/** <!----------------------------------------------------------------------------------------->
	 * If set to true, all SVN actions will be canceled (see also CheckForCancelCallback() )
	 <!-----------------------------------------------------------------------------------------> */
	bool m_bCanceled;


};	// END class SvnConnection

#endif // SVN_CONNECTION_H
